package com.yeskery.nut.event;

import com.yeskery.nut.bean.ApplicationContext;
import com.yeskery.nut.bean.BeanPostProcessor;
import com.yeskery.nut.bean.FactoryBeanRegister;
import com.yeskery.nut.util.ReflectUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

/**
 * 基础事件bean后置处理器
 * @author sunjay
 * 2023/9/5
 */
public abstract class BaseEventListenerBeanPostProcessor implements BeanPostProcessor {

    /** 应用事件广播器 */
    private volatile ApplicationEventMulticaster applicationEventMulticaster;

    @Override
    public void process(Object bean, Class<?> beanClass, ApplicationContext applicationContext, FactoryBeanRegister factoryBeanRegister) {
        Class<? extends Annotation> eventListenerAnnotationType = getEventListenerAnnotationType();
        for (Method method : ReflectUtils.getBeanAnnotationMethod(beanClass, eventListenerAnnotationType)) {
            Parameter[] parameters = method.getParameters();
            if (parameters.length > 1) {
                continue;
            }

            Annotation eventListenerAnnotation = method.getAnnotation(eventListenerAnnotationType);
            if (parameters.length == 1 && !ApplicationEvent.class.isAssignableFrom(parameters[0].getType())
                    && !parameters[0].getType().isAssignableFrom(getSupportApplicationEventType(eventListenerAnnotation))) {
                continue;
            }
            getApplicationEventMulticaster(applicationContext).addApplicationListener(getApplicationListener(bean, beanClass, method,
                    applicationContext, eventListenerAnnotation));
        }
    }

    /**
     * 获取应用事件广播器
     * @param applicationContext 应用上下文
     * @return 应用事件广播器
     */
    protected ApplicationEventMulticaster getApplicationEventMulticaster(ApplicationContext applicationContext) {
        if (applicationEventMulticaster == null) {
            synchronized (this) {
                if (applicationEventMulticaster == null) {
                    applicationEventMulticaster = applicationContext.getBean(ApplicationEventMulticaster.class);
                }
            }
        }
        return applicationEventMulticaster;
    }

    /**
     * 获取事件监听器注解类型
     * @return 事件监听器注解类型
     */
    protected abstract Class<? extends Annotation> getEventListenerAnnotationType();

    /**
     * 获取支持的事件类型
     * @param eventListenerAnnotation 事件监听器注解对象
     * @return 支持的事件类型
     */
    protected abstract Class<? extends ApplicationEvent> getSupportApplicationEventType(Object eventListenerAnnotation);

    /**
     * 获取事件监听器
     * @param bean bean对象
     * @param beanClass bean的类型
     * @param method 事件监听器方法对象
     * @param applicationContext 应用上下文
     * @param eventListenerAnnotation 事件监听器注解对象
     * @return 事件监听器
     */
    protected abstract ApplicationListener<?> getApplicationListener(Object bean, Class<?> beanClass, Method method,
                                                                     ApplicationContext applicationContext,
                                                                     Object eventListenerAnnotation);
}
